/*
* ============================================================================
*  Name        : sea_timer.h
*  Part of     : Finite state machine framework
*  Description : Timer class definition
*  Version     : %version: %
*  
*
* ============================================================================
*/

/**
 * @file sea_timer.h
 * @brief Life cycle timer
 *
 * @ingroup StateMachineFramework
 */
#include "sea_event.h"

#if !defined( __sea_timer_h__ )
#define __sea_timer_h__

namespace sea
{
    class StateMachine;
    class Event;

    /** 
     * @class Timer
     * @brief Life cycle timer
     *
     * @ingroup StateMachineFramework
     */
    class Timer: public Object
    {
        friend class TimerServer;
        friend class StateMachine;

    public:

        /**
         * To avoid holding timer server lock for a long time
         * need to have simple states for the timer
         */
        enum { NOT_ACTIVE, ACTIVE, TO_BE_FIRED };

        /**
         * Create life cycle timer
         *
         * @param handle               State machine handle
         * @param heart_beat_rate        Heart beat rate
         * @param heart_beats           Total number of heart beats
         * @param event_data            Event data
         * @param heart_beat_event_id     Heart beat event id, default: \b Ev_Sys_HeartBeat
         * @param last_heart_beat_event_id Last heart beat event id, default: \b EV_Sys_LastHeartBeat
         *
         * @return Error            Error code
         */
        Timer( StateMachine* handle, 
            int heart_beat_rate = 0,
            int heart_beats = 0,
            void* event_data = NULL, 
            EventId heart_beat_event_id = 0x80000003,
            EventId last_heart_beat_event_id = 0x80000004 );

        /**
         * Create life cycle timer. 
         *
         * @param heart_beat_rate    Heart beat rate
         * @param heart_beats       Total number of heart beats
         * @param callback         Callback function
         * @param callback_param    Callback parameter
         *
         * @return Error            Error code
         */
        Timer( int heart_beat_rate = 0,
            int heart_beats = 0,
            Callback callback = NULL,
            void* callback_param = NULL );

        /**
         * Start timer
         */
        void start( );

        /**
         * Stop timer
         */
        void stop( );

        /**
         * Stop and reset timer's counter
         */
        void reset( );

        /**
         * Get heartbeats limit
         */
        int heart_beats( ) { return m_heart_beats; }

        /**
         * Set heartbeats limit
         */
        void set_heart_beats( int heart_beats ) { m_heart_beats = heart_beats; }

        /**
         * Get heartbeat interval in ms
         *
         * @return heartbeat interval in ms
         */
        int heart_beat_rate( ) { return m_heart_beat_rate; }

        /**
         * Set heartbeat interval in ms
         *
         * @param heart_beat_rateMs heartbeat interval in ms
         */
        void set_heart_beat_rate( int heart_beat_rate_ms );

        /**
         * Get current heartbeat number
         *
         * @return current heartbeat number
         */
        int get_current_heart_beat( ) { return m_heart_beats_counter; }

        /**
         * Reset state machine handle. Use this API when timer holds 
         * a reference to a state machine this timer part of. That will
         * break cross reference that may lead to memory leaks
         */
        void forget_state_machine( );

    private:

        long get_start_time_stamp( ) { return m_start_time_stamp; } 
        void set_start_time_stamp( long timestamp ) { m_start_time_stamp = timestamp; } 

        bool is_last( ) { return m_heart_beats == m_heart_beats_counter; }
        void invoke_callback( );

    private:
        int m_state;                            ///< Yep, simplistic state
        sea::ref< StateMachine > m_handle;      ///< State machine handle
        int m_heart_beat_rate;                  ///< Heartbeat rate in ms
        int m_heart_beats;                      ///< Max number of heartbeats

        int m_heart_beats_counter;              ///< Current ongoing heartbeat
        int m_start_time_stamp;                 ///< Timestamp when timer was launched

        Callback m_callback;                    ///< User provided callback function
        void* m_data;                           ///< Callback parameter

        EventId m_heart_beat_event_id;          ///< Timeout event 
        EventId m_last_heart_beat_event_id;     ///< Last timeout event

        sea::ref< Event > m_event;              ///< Event to generate on timeout
        OsMutex m_lock;                         ///< Protect timer stop/start/setHeartBeatRate/invokeCallback
    };
}

#endif // #if !defined( __sea_timer_h__ )
